package com.xq.shop.aop.anno;

import com.alibaba.fastjson.JSONObject;
import com.xq.shop.config.Redis;
import com.xq.shop.dao.domain.entity.OperationLog;
import com.xq.shop.interceptor.AuthInterceptor;
import com.xq.shop.service.IOperationLogService;
import com.xq.shop.vo.UserVo;
import exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import utils.BaseResult;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @author gaoxiaojin
 */
@Aspect
@Component
@Slf4j
public class OperationAspect {

    @Resource
    private IOperationLogService operationLogService;
    @Resource
    private Redis redis;

    @Pointcut("@annotation(com.xq.shop.aop.anno.OperationAnnotation)")
    public void operationPointCut(){}

    @Around("operationPointCut()")
    public Object operationLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("记录操作日志--start");
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        assert sra != null;
        HttpServletRequest request = sra.getRequest();
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        String content = method.getAnnotation(OperationAnnotation.class).function();
        String url = request.getRequestURI();
        // 对系统进行操作后获取token
        String token = redis.existsLike(AuthInterceptor.getToken(request), 0);
        Object[] objects = proceedingJoinPoint.getArgs();
        UserVo userVo = (UserVo) redis.get(token);
        OperationLog operationLog = new OperationLog();
        long startTime = System.currentTimeMillis();
        Object result;
        BaseResult<?> apiResult = new BaseResult<>();
        try {
            result = proceedingJoinPoint.proceed();
            apiResult = (BaseResult<?>) result;
        } catch (Exception e) {
            // 异常处理逻辑
            log.error("目标方法执行发生异常: {}", e.getMessage());
            if (e instanceof BusinessException) {
                BusinessException be = (BusinessException) e;
                apiResult.setSuccess(false);
                apiResult.setCode(be.getCode());
                apiResult.setMessage(be.getMessage());
            } else {
                apiResult.setSuccess(false);
                apiResult.setMessage(e.getMessage());
            }
            throw e;
        } finally {
            Integer duration = Math.toIntExact(System.currentTimeMillis() - startTime);
            operationLog.setContent(content);
            operationLog.setUserId(userVo.getId());
            operationLog.setUsername(userVo.getUsername());
            operationLog.setRequestArgs(JSONObject.toJSONString(Arrays.toString(objects)));
            operationLog.setReturnValue(JSONObject.toJSONString(apiResult));
            operationLog.setDuration(duration);
            operationLog.setRequestUrl(url);
            operationLogService.save(operationLog);
            log.info("操作日志信息：{}", operationLog);
            log.info("记录操作日志--end");
        }
        return result;
    }
}
